home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HyperLib 1997 Winter - Disc 1
/
HYPERLIB-1997-Winter-CD1.ISO.7z
/
HYPERLIB-1997-Winter-CD1.ISO
/
オンラインウェア
/
UTIL
/
Natural Order.sit
/
Natural Order
/
Sources
/
Natural Order.c
next >
Wrap
C/C++ Source or Header
|
1996-11-04
|
9KB
|
231 lines
// Natural Order
// ゥ1996 Stuart Cheshire <cheshire@CS.Stanford.EDU>
//
// Natural Order patches IUMagString and IUMagPString to make them sort strings containing
// numbers in a sensible order
// See Natural Order ReadMe for more details
// See TextUtils.h for the declaration of IUMagString, IUMagPString etc.
#include <Traps.h>
#include "StuTypes.h"
// If USE_SYS_PACK6 is set to 1, the patch calls through to the underlying system sorting routine
// to sort the textual parts of the strings. This preserves language-specific sorting orders.
// If USE_SYS_PACK6 is set to 0, the patch does entirely self-contained sorting, using only lexico-
// graphic sorting of the textual parts of the strings based on the ASCII values of the characters.
#define USE_SYS_PACK6 1
#define isdigit(X) ((X) >= '0' && (X) <= '9')
void main(void);
pascal short my_pack6(...);
pascal short sys_pack6(const u_char *aPtr, const u_char *bPtr, short aLen, short bLen,
Handle itl2Handle, short TrapSelector);
#define SysMagPString(A,B,C,D,E) sys_pack6((A),(B),(C),(D),(E),0x001A)
local pascal short StuMagString(const u_char *aPtr, const u_char *bPtr, short aLen, short bLen,
short TrapSelector);
local pascal short StuMagPString(const u_char *aPtr, const u_char *bPtr, short aLen, short bLen,
Handle itl2Handle, short TrapSelector);
// entry_point must be the first routine in the file
local void entry_point(void) /* no stack frame please ! */
{
asm {
@0 move.l a0, -(sp)
DetachResource
bra main
extern my_pack6: cmp.w #0x000A, 4(sp) ; IUMagString
beq StuMagString
cmp.w #0x001A, 4(sp) ; IUMagPString
beq StuMagPString
extern sys_pack6: jmp 0x12345678
}
}
#if USE_SYS_PACK6
// This version of StuMagPString calls through to the system's IUMagPString routine for
// comparing the textual parts of strings.
// See below for a self-contained version
// If string a sorts before b, return -1, else if b sorts before a, return 1, else return 0
local pascal short StuMagPString
(const u_char *aPtr, const u_char *bPtr, short aLen, short bLen, Handle itl2Handle, short TrapSelector)
{
short result;
long zeroskip = 0;
const u_char *a = aPtr, *aEnd = a + aLen;
const u_char *b = bPtr, *bEnd = b + bLen;
// While *either* string has any characters left, continue.
while (aPtr < aEnd || bPtr < bEnd)
{
// At first entry to the loop:
// a = aPtr = start of string a, and likewise b = bPtr = start of string b
// On subsequent passes:
// Everything up to aPtr/bPtr has been compared already and found to be equal
// aPtr/bPtr point to the next characters to be compared (which may be digits)
// a/b point to the first non-digit characters in each string
// Find end of non-digit characters in each string
// (i.e. no more characters left, or a character that's a digit)
while (a < aEnd && !isdigit(*a)) a++;
while (b < bEnd && !isdigit(*b)) b++;
// Compare what we've got so far
// (possibly leading digits, possibly followed by non-digit characters)
result = SysMagPString(aPtr, bPtr, a-aPtr, b-bPtr, itl2Handle);
// If they're unequal, we're finished
if (result) return (result);
// If they're otherwise equal but we skipped a different number of zeroes
// in getting here, use that information to break the tie
if (zeroskip > 0) return(1); else if (zeroskip < 0) return(-1);
// No, they're really completely equal, so we continue
// Skip over leading zeroes on numbers (but not a single lone zero)
// We count the number of skipped zeroes in case we need it as a tie breaker later
while (a[0] == '0' && a < aEnd-1 && isdigit(a[1])) { a++; zeroskip++; }
while (b[0] == '0' && b < bEnd-1 && isdigit(b[1])) { b++; zeroskip--; }
// Record where we're at (everything to here has been deemed 'equal')
aPtr = a;
bPtr = b;
// Read all the digits, and see if one runs out first.
while (a < aEnd && isdigit(*a) && b < bEnd && isdigit(*b)) { a++; b++; }
// Now, at least one of a or b does not point to a digit
// If string a has a digit left (and b doesn't) then, trivially, a is greater
if (a < aEnd && isdigit(*a)) return(1);
// If string b has a digit left (and a doesn't) then, trivially, b is greater
if (b < bEnd && isdigit(*b)) return(-1);
// Neither have digits left, so both have equal-length numbers, so go around the loop
// a second time and let SysMagPString be responsible for lexicographically comparing the
// numbers (lexicographic comparison works for numbers that are equal-length digit sequences).
}
// Both strings ran out. That means they must be 'equal'
return(0);
}
#else
// This version of StuMagPString is completely self-contained. It does not call through
// to the system's IUMagPString routine and it has no knowledge of language-specific
// characteristics,such as how characters with accents should sort.
// It should never normally be used as a patch for the system's IUMagPString routine, but the
// code is included here simply as sample code for people who want to incorporate Natural Order's
// sensible numeric sorting without the cost of calling the Mac's IU sorting routines.
// See above for a version that respects the system's sorting order.
// If string a sorts before b, return -1, else if b sorts before a, return 1, else return 0
local pascal short StuMagPString
(const u_char *aPtr, const u_char *bPtr, short aLen, short bLen, Handle itl2Handle, short TrapSelector)
{
short result;
long zeroskip = 0;
const u_char *a, *aEnd = aPtr + aLen;
const u_char *b, *bEnd = bPtr + bLen;
// While *either* string has any characters left, continue.
while (aPtr < aEnd || bPtr < bEnd)
{
// Compare non-digit characters.
while (aPtr < aEnd && bPtr < bEnd)
{
u_char ac = *aPtr;
u_char bc = *bPtr;
if (isdigit(ac) && isdigit(bc)) break; // If both are digits, break out
if (ac < bc) return(-1); else if (ac > bc) return(1);
aPtr++;
bPtr++;
}
if (aPtr == aEnd && bPtr == bEnd) return(0); // If both strings ran out, they're equal
if (aPtr == aEnd) return(-1); // If A ran out (and B didn't), A is less
if (bPtr == bEnd) return(1); // If B ran out (and A didn't), B is less
// If they're otherwise equal but we skipped a different number of zeroes
// in getting here, use that information to break the tie
if (zeroskip > 0) return(1); else if (zeroskip < 0) return(-1);
// No, they're really completely equal, so we continue
// Skip over leading zeroes on numbers (but not a single lone zero)
// We count the number of skipped zeroes in case we need it as a tie breaker later
while (aPtr[0] == '0' && aPtr < aEnd-1 && isdigit(aPtr[1])) { aPtr++; zeroskip++; }
while (bPtr[0] == '0' && bPtr < bEnd-1 && isdigit(bPtr[1])) { bPtr++; zeroskip--; }
// Record where we're at (everything to here has been deemed 'equal')
a = aPtr;
b = bPtr;
// Read all the digits, and see if one runs out first.
while (a < aEnd && isdigit(*a) && b < bEnd && isdigit(*b)) { a++; b++; }
// Now, at least one of a or b does not point to a digit
// If string a has a digit left (and b doesn't) then, trivially, a is greater
if (a < aEnd && isdigit(*a)) return(1);
// If string b has a digit left (and a doesn't) then, trivially, b is greater
if (b < bEnd && isdigit(*b)) return(-1);
// Neither have digits left, so both have equal-length numbers, so use
// lexicographical comparison decide which is greater (lexicographic
// comparison works for numbers that are equal-length digit sequences).
while (aPtr < a && bPtr < b)
{
if (*aPtr < *bPtr) return(-1); else if (*aPtr > *bPtr) return(1);
aPtr++;
bPtr++;
}
}
// Both strings ran out. That means they must be 'equal'
return(0);
}
#endif
local pascal short StuMagString
(const u_char *aPtr, const u_char *bPtr, short aLen, short bLen, short TrapSelector)
{
return(StuMagPString(aPtr, bPtr, aLen, bLen, NULL, TrapSelector));
}
local Boolean TrapAvailable(u_long trap)
{
TrapType tType = (trap & 0x800 ? ToolTrap : OSTrap);
if (trap & 0x800) // if it is a ToolBox Trap
{
u_long n = 0x400; // number of toolbox traps
if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
n = 0x200;
if ((trap &= 0x7FF) >= n) trap = _Unimplemented;
}
return(NGetTrapAddress(trap, tType) != NGetTrapAddress(_Unimplemented, ToolTrap));
}
typedef struct { WORD jmp; ProcPtr addr; } jmp;
#define TBpatch(VEC,T,NEW) p=&((jmp*)VEC)->addr; ¥
*p = GetToolTrapAddress(T); SetToolTrapAddress((ProcPtr)NEW,T)
#define OSpatch(VEC,T,NEW) p=&((jmp*)VEC)->addr; ¥
*p = GetOSTrapAddress(T); SetOSTrapAddress((ProcPtr)NEW,T)
export void main(void)
{
register ProcPtr *p;
TBpatch(sys_pack6, _Pack6, my_pack6);
if (TrapAvailable(_HWPriv)) FlushInstructionCache();
}